package com.seres.util;

import cn.hutool.core.util.ObjectUtil;
import com.seres.vo.BaseTree;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * @author Tan-Bowen
 * @version 1.0
 * @description TODO
 * @date 2021/9/23 10:50
 */
public class TreeTools {


    /**
     * @param [all, pid, id]
     * @return java.util.List<T>
     * @author Tan-Bowen
     * @description TODO 获取树结构数据
     * @date 2021/9/23 15:37
     * @paramType [java.util.List<T>, java.util.function.Function<T,E>, java.util.function.Function<T,E>]
     */
    public static <T extends BaseTree<T>, E> List<T> getTree(List<T> all, Function<T, E> pid, Function<T, E> id) {
        Map<E, T> map = StreamTools.toMap(all, id);
        List<T> result = new ArrayList<>();
        for (T t : all) {
            T parent = map.get(pid.apply(t));
            if (ObjectUtil.isNotNull(parent)) {
                List<T> child = parent.getChildren();
                if (!ValidatorTools.notEmpty(child)) {
                    child = new ArrayList<>();
                    parent.setChildren(child);
                }
                child.add(t);
            } else {
                result.add(t);
            }
        }
        return result;
    }


    /**
     * @param [all, parent, e]
     * @return java.util.List<T>
     * @author Tan-Bowen
     * @description TODO 获取所有子级
     * @date 2021/9/23 10:49
     * @paramType [java.util.List<T>, java.util.function.Function<T,E>, E]
     */
    public static <T, E> List<T> getChildes(List<T> all, E e, Function<T, E> parentId, Function<T, E> id) {
        Map<E, List<T>> map = StreamTools.group(all, parentId);
        List<T> sons = map.get(e);
        if (ValidatorTools.isEmpty(sons)) {
            return Collections.emptyList();
        }
        List<T> result = new ArrayList<>(sons);
        return getGrandSon(sons, result, map, id);
    }

    public static <T, E> List<T> getGrandSon(List<T> sons, List<T> result, Map<E, List<T>> map, Function<T, E> id) {
        if (ValidatorTools.isEmpty(sons)) {
            return result;
        }
        List<T> son = new ArrayList<>();
        sons.forEach(item -> {
            List<T> grandSon = map.get(id.apply(item));
            if (ValidatorTools.notEmpty(grandSon)) {
                result.addAll(grandSon);
                son.addAll(grandSon);
            }
        });
        sons = null;
        return getGrandSon(son, result, map, id);
    }
}
